package com.example.lotterysystem.service.impl;

import cn.hutool.crypto.digest.DigestUtil;
import com.example.lotterysystem.common.errorcode.ServiceErrorCodeConstants;
import com.example.lotterysystem.common.exception.ServiceException;
import com.example.lotterysystem.common.utils.JWTUtil;
import com.example.lotterysystem.common.utils.MyCaptureUtil;
import com.example.lotterysystem.common.utils.RegexUtil;
import com.example.lotterysystem.common.utils.SMSUtil;
import com.example.lotterysystem.controller.param.ShortMessageLoginParam;
import com.example.lotterysystem.controller.param.UserLoginParam;
import com.example.lotterysystem.controller.param.UserLoginPasswordParam;
import com.example.lotterysystem.controller.param.UserRegisterParam;
import com.example.lotterysystem.dao.dataobject.Encrypt;
import com.example.lotterysystem.dao.dataobject.UserDO;
import com.example.lotterysystem.dao.mapper.UserMapper;
import com.example.lotterysystem.service.UserService;
import com.example.lotterysystem.service.VerificationCodeService;
import com.example.lotterysystem.service.dto.UserDTO;
import com.example.lotterysystem.service.dto.UserLoginDTO;
import com.example.lotterysystem.service.dto.UserRegisterDTO;
import com.example.lotterysystem.service.enums.UserIdentityEnum;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private VerificationCodeService verificationCodeService;

    /**
     * 用户注册
     * @param param
     * @return
     */
    @Override
    public UserRegisterDTO register(UserRegisterParam param) {

        //1.参数校验
        checkRegisterInfo(param);

        //2.对数据进行加密,并构造请求
        UserDO userDO=new UserDO();
        userDO.setUserName(param.getName());
        userDO.setEmail(param.getMail());
        userDO.setIdentity(param.getIdentity());
        userDO.setPhoneNumber(new Encrypt(param.getPhoneNumber()));
        //如果是注册管理员，要先判断是否输入密码
        if(StringUtils.hasText(param.getPassword())){
            userDO.setPassword(DigestUtil.sha256Hex(param.getPassword()));
        }

        //3.保存数据
        userMapper.insert(userDO);
        //4.构造返回数据
        UserRegisterDTO registerDTO=new UserRegisterDTO();
        registerDTO.setUserId(userDO.getId());
        return registerDTO;
    }

    /**
     * 用户登录
     * @param param
     * @return
     */
    @Override
    public UserLoginDTO login(UserLoginParam param) {
        UserLoginDTO userLoginDTO;
        //1.先判断是密码登录还是验证码登录
        if (param  instanceof UserLoginPasswordParam userLoginParam){
            //密码登录
            userLoginDTO = loginByPassword(userLoginParam);
        }else if (param instanceof ShortMessageLoginParam userLoginParam){
            //验证码登录
            userLoginDTO = loginByShortMessage(userLoginParam);
        }else {
            throw new ServiceException(ServiceErrorCodeConstants.LOGIN_INFO_NOT_EXIT);
        }
        return userLoginDTO;
    }

    /**
     * 根据identity查询人员列表
     * @param identity
     * @return
     */
    @Override
    public List<UserDTO> findUserInfo(UserIdentityEnum identity) {
        //在数据库中，是根据String类型去查的，所以要对identity进行转化
        String userIdentity = identity==null ? null : identity.name();
        //根据identity去数据库查询相关信息
        List<UserDO> userDOList = userMapper.selectUserListByIdentity(userIdentity);
        //构造成List<UserDTO>类型返回
        List<UserDTO> userDTOList = userDOList.stream()
                .map(userDO->{
                    UserDTO userDTO=new UserDTO();
                    userDTO.setUserId(userDO.getId());
                    userDTO.setUserName(userDO.getUserName());
                    userDTO.setEmail(userDO.getEmail());
                    userDTO.setPhoneNumber(userDO.getPhoneNumber().getValue());
                    userDTO.setIdentity(UserIdentityEnum.forName(userDO.getIdentity()));
                    return userDTO;
                }).collect(Collectors.toList());
        return userDTOList;
    }

    /**
     * 短信验证登录
     * @param userLoginParam
     * @return
     */
    private UserLoginDTO loginByShortMessage(ShortMessageLoginParam userLoginParam) {
        UserDO userDO;
        //1.验证手机号
        if (RegexUtil.checkMobile(userLoginParam.getLoginMobile())){
            userDO = userMapper.selectByPhoneNumber(new Encrypt(userLoginParam.getLoginMobile()));
        }else {
            throw new ServiceException(ServiceErrorCodeConstants.LOGIN_NOT_EXIT);
        }

        //2.校验userDo是否为null
        if (userDO == null){
            throw new ServiceException(ServiceErrorCodeConstants.USER_INFO_NOT_EXIT);
        }else if (StringUtils.hasText(userLoginParam.getMandatoryIdentity())
                && !userLoginParam.getMandatoryIdentity().equalsIgnoreCase(userDO.getIdentity()) ){
            throw new ServiceException(ServiceErrorCodeConstants.IDENTITY_ERROR);
        }
        //3.验证code是否正确
        String code=verificationCodeService.getVerificationCode(userLoginParam.getLoginMobile());
        if (!userLoginParam.getVerificationCode().equals(code)){
            throw  new ServiceException(ServiceErrorCodeConstants.CODE_ERROR);
        }else {
            //4.生成JWT令牌
            Map<String,Object> claim=new HashMap<>();
            claim.put("id",userDO.getId());
            claim.put("identity",userDO.getIdentity());
            String token=JWTUtil.genJwt(claim);
            UserLoginDTO userLoginDTO=new UserLoginDTO();
            userLoginDTO.setToken(token);
            userLoginDTO.setIdentity(UserIdentityEnum.forName(userDO.getIdentity()));
            return userLoginDTO;
        }
    }

    /**
     * 密码登录
     * @param userLoginParam
     * @return
     */
    private UserLoginDTO loginByPassword(UserLoginPasswordParam userLoginParam) {
        UserDO userDO=null;
        //1.判断LoginName是手机号还是邮箱
        if (RegexUtil.checkMobile(userLoginParam.getLoginName())){
            //LoginName是手机号，根据手机号从数据库中查询相关的用户信息
            userDO = userMapper.selectByPhoneNumber(new Encrypt(userLoginParam.getLoginName()));
        }else if (RegexUtil.checkMail(userLoginParam.getLoginName())){
            //LoginName是邮箱，根据邮箱从数据库中查询相关的用户信息
            userDO = userMapper.selectByMail(userLoginParam.getLoginName());
        }else {
            throw new ServiceException(ServiceErrorCodeConstants.LOGIN_NOT_EXIT);
        }
        //2.校验用户身份，是否强制身份登录
        //先判断userDo是否为空
        if (userDO == null){
            throw new ServiceException(ServiceErrorCodeConstants.USER_INFO_NOT_EXIT);
        }else if (StringUtils.hasText(userLoginParam.getMandatoryIdentity())
                && !userLoginParam.getMandatoryIdentity().equalsIgnoreCase(userDO.getIdentity())){
            //存在强制登录身份，判断身份是否匹配
            throw new ServiceException(ServiceErrorCodeConstants.IDENTITY_ERROR);
        }else if (!DigestUtil.sha256Hex(userLoginParam.getPassword()).equals(userDO.getPassword())){
            //校验密码是否正确
            throw new ServiceException(ServiceErrorCodeConstants.PASSWORD_ERROR);
        }
        //生成token
        Map<String,Object> claim = new HashMap<>();
        claim.put("id",userDO.getId());
        claim.put("identity",userDO.getIdentity());
        String token = JWTUtil.genJwt(claim);
        //返回结果
        UserLoginDTO userLoginDTO =new UserLoginDTO();
        userLoginDTO.setIdentity(UserIdentityEnum.forName(userDO.getIdentity()));
        userLoginDTO.setToken(token);
        return userLoginDTO;
    }

    private void checkRegisterInfo(UserRegisterParam param) {
        //1.对param进行判空
        if(param==null){
            throw new ServiceException(ServiceErrorCodeConstants.REGISTER_INFO_IS_EMPTY);
        }

        //校验邮箱格式
        if(!RegexUtil.checkMail(param.getMail())){
            throw new ServiceException((ServiceErrorCodeConstants.MAIL_ERROR));
        }

        //校验手机号格式
        if (!RegexUtil.checkMobile(param.getPhoneNumber())){
            throw new ServiceException(ServiceErrorCodeConstants.PHONE_NUMBER_ERROR);
        }

        //校验身份信息是否在枚举类型内
        if (UserIdentityEnum.forName(param.getIdentity())==null){
            throw new ServiceException(ServiceErrorCodeConstants.IDENTITY_ERROR);
        }

        //校验管理员是否输入密码
        if (param.getIdentity().equalsIgnoreCase(UserIdentityEnum.ADMIN.name())
                && !StringUtils.hasText(param.getPassword())){
            throw new ServiceException(ServiceErrorCodeConstants.PASSWORD_IS_EMPTY);
        }

        //校验密码格式，至少为6位
        if (StringUtils.hasText(param.getPassword()) && !RegexUtil.checkPassword(param.getPassword())){
            throw new ServiceException(ServiceErrorCodeConstants.PASSWORD_ERROR);
        }

        //校验邮箱是否被注册过
        //查询数据库是否有这个邮箱即可
        if (checkMailUsed(param.getMail())){
            throw new ServiceException(ServiceErrorCodeConstants.MAIL_USED);
        }

        //校验手机号是否被使用
        if(checkPhoneNumberUsed(param.getPhoneNumber())){
            throw new ServiceException(ServiceErrorCodeConstants.PHONE_NUMBER_USED);
        }
    }

    //校验手机号是否被使用
    private boolean checkPhoneNumberUsed(String phoneNumber) {
        int count=userMapper.countByPhone(new Encrypt(phoneNumber));
        return count>0;
    }

    //校验邮箱号是否被使用
    private boolean checkMailUsed(String mail) {
        //调用dao层，查询相关信息
        int count=userMapper.countByMail(mail);
        return count>0;
    }

}
